package com.haiyou.common.spring.log.warning.service;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import com.google.common.collect.Maps;
import com.google.common.eventbus.Subscribe;
import com.haiyou.common.event.asyc.AbstractAsyncEventObserver;
import com.haiyou.common.spring.log.warning.event.ExceptionLogEvent;
import com.haiyou.common.spring.schedule.ActorScheduledExecutor;
import com.haiyou.common.system.Properties;
import com.haiyou.common.thread.ThreadManager;
import com.haiyou.common.thread.ThreadManager.ThreadEnum;
import com.haiyou.common.thread.task.AbstractOrderedTask;
import com.haiyou.common.util.ip.IpUtil;
import com.haiyou.common.util.log.LogCounter;
import com.haiyou.common.util.string.StringFormatUitls;
import com.haiyou.common.util.system.PidUtils;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.util.ContextSelectorStaticBinder;
import lombok.extern.slf4j.Slf4j;

/**
 * 
 * @Description: 异常日志告警业务
 * @author xingyuan
 * @date 2023年3月30日 上午11:57:14
 */
@Slf4j
@Component
public class ExceptionLogWarningService extends AbstractAsyncEventObserver{

	/**
	 * 日志格式化
	 */
	private static final PatternLayout layout = new PatternLayout();
	
	private static final String mail_subject_format = "服务器IP {},pid {},出现异常日志";

	private static final String mail_text_format = "项目目录 {} \n {}";
	
	private static final String ser = "log";
	
	/**
	 * 单线程池
	 */
	private static ExecutorService executor;
	
	/**
	 * 计数器
	 */
	private static Map<String, LogCounter> counter = Maps.newConcurrentMap();
	
	static {
		
		try {
			//从log中获取
			Field field = log.getClass().getDeclaredField("loggerContext");
			field.setAccessible(true);
			LoggerContext loggerContext = (LoggerContext) field.get(log);
			
			layout.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSSS} [%thread] %-5level %logger{36}-[Line:%L]>%m%n");
			layout.setContext(loggerContext);
			layout.start();
			
			executor = new ActorScheduledExecutor(ThreadManager.getThreadCount(ThreadEnum.log_listener_thread), "log-listener");
		} catch (Exception e) {
			
		}
	}
	
	
	@Autowired
	private LogWarningMailService mailSender;

	/**
	 * 执行
	 * @param runnable
	 */
	public void execute(AbstractOrderedTask<Object> runnable) {
		executor.execute(runnable);
	}
	
	/**
	 * 发送邮件
	 * @param tos
	 * @param text
	 * @param subject
	 */
	public void sendMail(Set<String> tos,String text, String subject) {
		   
		SimpleMailMessage message = new SimpleMailMessage();
      
		
//	    message.setFrom(mailSender.getSenderMail());
		message.setFrom("服务器日志监控" + '<' + mailSender.getSenderMail() + '>');

        message.setTo(tos.toArray(new String[tos.size()]));
        message.setSubject(subject);
        message.setText(text);
        
        mailSender.getJavaMailSender().send(message);
	}
	
	/**
	 * 异常监控事件
	 * @param event
	 */
	@Subscribe
	public void recv(ExceptionLogEvent event) {

		execute(new AbstractOrderedTask<Object>(ser) {
		
			@Override
			protected void exec() throws Exception {

				try {
					ILoggingEvent logEvent = event.getEvent();

					if (logEvent == null) {
						return;
					}

					// class 名称
					String className = event.getEvent().getThrowableProxy().getClassName();

					LogCounter logCounter = counter.getOrDefault(className, null);

					if (logCounter == null) {
						logCounter = new LogCounter();
						counter.put(className, logCounter);
					}

					logCounter.addTimes();

					if (logCounter.limit()) {
						return;
					}

					Set<String> mails = Properties.log_warning_mails();

					if (ObjectUtils.isEmpty(mails)) {
						return;
					}

					// 文本格式化
					String text = StringFormatUitls.format(mail_text_format, System.getProperty("user.dir"),
							layout.doLayout(logEvent));

					// 标题
					String subject = StringFormatUitls.format(mail_subject_format, IpUtil.getLocalIP(),
							PidUtils.getPid());

					// 推送邮件
					sendMail(mails, text, subject);

				} catch (Exception e) {
					log.error("send error mail fail.");
				}
			}
		});
		
	}
	

	
	

}
